package info.fqtech.skb.demo.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import info.fqtech.skb.demo.utils.HttpUtils;
import info.fqtech.skb.demo.utils.MerchantConfig;
import info.fqtech.skb.demo.utils.SignUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author YASSER
 * @version: 1.0.0
 * @description: 商户下单接口对接demo
 * @modified: <文件修改说明>
 */
@RestController
@RequestMapping("/pay")
public class PayController {

    private final static Logger logger = LoggerFactory.getLogger(PayController.class);

    /**
     * 模拟客户端下单接口
     * @param amount -- 支付金额，单位元，2位小数
     * @return
     */
    @RequestMapping("/makeOrder")
    public Object makeOrder(double amount) {
        // 创建订单号，需要商户内唯一，6-18位以内的纯数字
        String orderNo = String.valueOf(System.currentTimeMillis());
        Map<String, String> requestMap = new HashMap<>(6);
        // 商户号
        requestMap.put("merCode", MerchantConfig.MER_CODE);
        requestMap.put("makeOrderType", MerchantConfig.MAKE_ORDER_TYPE);
        // 默认值，充值渠道：0支付宝，1微信，2QQ
        requestMap.put("payChannelType", "0");
        // 收款账号
        requestMap.put("merAccount", MerchantConfig.MER_ACCOUNT);
        // 订单金额，单位元，2位小数
        requestMap.put("orderAmount", formatAmount(amount));
        // 支付结果回调通知地址
        requestMap.put("notifyUrl", MerchantConfig.PAY_ORDER_NOTIFY_URL);
        // 订单号，唯一，40位以内的纯数字
        requestMap.put("orderNo", orderNo);
        // 生成签名
        String sign = SignUtils.getSignOfMD5(requestMap, MerchantConfig.MER_KEY);
        requestMap.put("sign", sign);
        logger.info("requestMap:{}", requestMap);
        // 发起获取支付数据请求
        String responseStr = HttpUtils.doPost(MerchantConfig.PAY_ORDER_GATEWAY, requestMap);
        // 解析获取到的json字符串
        /**
         * 返回的数据为:
         * {
         *    "status": true|false, -- 下单成功true或失败false
         *    "code": "1000", --- 消息编码，具体含义查看编码含义表
         *    "msg": "status为false时有值，显示失败原因",
         *    "merCode": "商户号", -- status=true时有值
         *    "makeOrderType": "创建订单方式：0指定账号产出，1轮询方式产出", -- status=true时有值
         *    "payChannelType": "支付渠道类型：0支付宝，1微信，2QQ", -- status=true时有值
         *    "orderNo": "订单号", -- status=true时有值
         *    "orderAmount": "订单金额，单位元，2位小数", -- status=true时有值
         *    "realAmount": "实际应支付金额，单位元，2位小数", -- status=true时有值
         *    "qrCodeUrl": "支付宝付款链接，可以在手机浏览器中直接打开，将会自动跳转到支付宝付款；也可以生成二维码使用支付宝扫码付款",
         *    "sign": "签名数据"
         * }
         */
        JSONObject jsonObject = JSON.parseObject(responseStr);
        if(jsonObject.getBoolean("status") && Objects.equals("1000", jsonObject.get("code"))) {
            // 如果status为true 和  code为1000。则表示下单成功
            // 处理下单成功后的业务逻辑

            // ......

        }else {
            // 表示下单失败的后续业务逻辑

        }
        return jsonObject;
    }


    /**
     * 处理支付结果的回调通知
     * @param status -- 状态 ： true成功，false失败
     * @param code -- 消息编码
     * @param msg -- 消息内容
     * @param merCode -- 商户号，status=true时有值
     * @param payChannelType -- 支付渠道，status=true时有值
     * @param orderNo -- 订单号，status=true时有值
     * @param orderAmount -- 订单金额，单位元，2位小数，status=true时有值
     * @param realPayAmount -- 订单实际支付金额，单位元，2位小数，status=true时有值
     * @param sign -- 数据签名，status=true时有值
     * @param request
     * @param response
     * @throws IOException
     */
    @RequestMapping("/notify")
    public void handleNotify(String status,
                             String code,
                             String msg,
                             String merCode,
                             String payChannelType,
                             String orderNo,
                             String orderAmount,
                             String realPayAmount,
                             String sign,
                             HttpServletRequest request, HttpServletResponse response) throws IOException {
        Map<String, String> notifyMap = new HashMap<>(5);
        notifyMap.put("merCode", merCode);
        notifyMap.put("payChannelType", payChannelType);
        notifyMap.put("orderNo", orderNo);
        notifyMap.put("orderAmount", orderAmount);
        notifyMap.put("realPayAmount", realPayAmount);
        logger.info("回调通知数据:{}", notifyMap);
        // 处理结果返回字符串
        String handleResultStr = "签名错误";
        // 计算签名
        String md5Sign = SignUtils.getSignOfMD5(notifyMap, MerchantConfig.MER_KEY);
        if(Objects.equals(md5Sign, sign)) {
            if (Objects.equals(status, String.valueOf(Boolean.TRUE)) && Objects.equals("1015", code)){
                // 如果status为true 和 code = 1015 表示付款成功

                // 处理付款成功业务逻辑。此处需要防止重复通知

                // ......

                // 处理成功
                handleResultStr =  "SUCCESS";
            }
        }
        // 将处理结果返回给收款吧系统，如果返回SUCCESS，则表示处理成功，则收款吧系统不再发起通知。否则收款吧会定时3分钟再次发起，总共发起3次
        PrintWriter printWriter = response.getWriter();
        printWriter.write(handleResultStr);
        printWriter.flush();
    }

    /**
     * 将订单金额格式化为2位小数的字符串
     * @param amount -- 订单金额，单位元，2位小数
     * @return
     */
    private String formatAmount(double amount) {
        BigDecimal bigDecimal = new BigDecimal(String.valueOf(amount));
        return bigDecimal.setScale(2, BigDecimal.ROUND_DOWN).toString();
    }

    /**
     * 查询订单状态
     * eg:
     * http://localhost:8010/client/pay/queryOrderStatus?orderNo=1541322153427
     * @param orderNo -- 订单号
     * @return
     */
    @RequestMapping("/queryOrderStatus")
    public Object queryOrderStatus(String orderNo) {
        if(StringUtils.isBlank(orderNo)) {
            return null;
        }
        Map<String, String> requestMap = new HashMap<>(3);
        // 商户号
        requestMap.put("merCode", MerchantConfig.MER_CODE);
        // 订单号，唯一，6-18位以内的纯数字
        requestMap.put("orderNo", orderNo);
        // 生成签名
        String sign = SignUtils.getSignOfMD5(requestMap, MerchantConfig.MER_KEY);
        requestMap.put("sign", sign);
        logger.info("requestMap:{}", requestMap);
        // 发起获取支付数据请求
        String responseStr = HttpUtils.doGet(MerchantConfig.QUERY_PAY_ORDER_STATUS_GATEWAY, requestMap);
        logger.info("查询订单状态响应数据:{}", responseStr);
        JSONObject jsonObject = null;
        if (StringUtils.isNotBlank(responseStr)) {
            // 解析获取到的json字符串
            /**
             * 返回的数据格式如下：
             {
             "msg": "订单支付成功-回调通知成功",
             "merCode": "8001", -- 商户号
             "realAmount": "1.00", -- 实际支付金额，单位元
             "code": "1017", -- 响应编码
             "orderNo": "1541322153427", -- 订单号
             "orderAmount": "1.00", -- 订单金额
             "sign": "629a6b73650d5b4c434e8cb8264c9be5", -- 数据签名
             "status": true -- true支付成功或false支付失败
             }
             */
            jsonObject = JSON.parseObject(responseStr);
            if(jsonObject.getBoolean("status")) {
                // 如果status为true 和  code为1015、1016、1017、1018、1019、1020。则表示订单支付成功
                // 处理订单支付成功的后续业务逻辑

                // ......

            }else {
                // 表示订单支付失败，处理后续业务逻辑

            }
        }
        return jsonObject;
    }
}
